package org.argus.management.system.service;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.argus.common.core.enums.UserType;
import org.argus.common.web.core.security.TokenManager;
import org.argus.common.web.core.snowflake.SnowflakeIdGenerator;
import org.argus.management.domain.Menu;
import org.argus.management.system.mapper.MenuMapper;
import org.argus.management.system.model.MenuRoute;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 刘文/Cliff Liu
 * @Date 2024/5/30
 */
@Service
public class MenuService {

    @Autowired
    private MenuMapper mapper;

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    @Autowired
    private TokenManager tokenManager;

    public List<Menu> search(String menuName) {
        if (StringUtils.isNotBlank(menuName)) {
            return mapper.selectList(Wrappers.lambdaQuery(Menu.class).like(Menu::getName, menuName));
        }
        return mapper.selectList(Wrappers.lambdaQuery(Menu.class));
    }

    public void add(Menu menu) {
        menu.setId(snowflakeIdGenerator.nextId());
        mapper.insert(menu);
    }

    public void modify(Menu menu) {
        mapper.updateById(menu);
    }

    @Transactional(rollbackFor = Exception.class)
    public int delete(Long id) {
        List<Long> ids = new LinkedList<>();
        List<Long> parentIds = Arrays.asList(id);
        while (!parentIds.isEmpty()) {
            ids.addAll(parentIds);
            parentIds = getChildren(parentIds).stream().map(Menu::getId).collect(Collectors.toList());
        }
        return mapper.delete(Wrappers.lambdaQuery(Menu.class).in(Menu::getId, ids));
    }

    public List<Menu> getChildren(List<Long> parentIds) {
        return mapper.selectList(Wrappers.lambdaQuery(Menu.class).in(Menu::getParentId, parentIds));
    }

    public List<Menu> getRoleMenu() {
        return mapper.selectList(null);
    }

    public List<MenuRoute> getUserMenus() {
        String userType = tokenManager.getUserType();
        List<Menu> allMenus = mapper.selectList(null);
        Set<Long> hasRightMenuIds;
        if (UserType.SUPER.toString().equals(userType)) {
            hasRightMenuIds = allMenus.stream().map(Menu::getId).collect(Collectors.toSet());
        }
        else{
            Long userId = tokenManager.getUserId();
            hasRightMenuIds = mapper.getUserHasRightMenus(userId);
        }
        Set<MenuRoute> middleMenus = new HashSet<>();
        Set<MenuRoute> rootMenus = new HashSet<>();
        Map<Long, MenuRoute> idToMenuRouteMap = new HashMap<>();
        for (Menu menu : allMenus) {
            MenuRoute menuRoute = convertMenuRoute(menu);
            idToMenuRouteMap.put(menu.getId(), menuRoute);
            // 有权限的菜单
            if (hasRightMenuIds.contains(menu.getId())) {
                if (menu.getParentId() == null) {
                    rootMenus.add(menuRoute);
                }
                // 需要逐级向上查找菜单
                else{
                    middleMenus.add(menuRoute);
                }
            }
        }

        // 逐级查找父菜单
        while (!middleMenus.isEmpty()) {
            Set<MenuRoute> newMiddleMenus = new HashSet<>();
            for (MenuRoute menuRoute : middleMenus) {
                MenuRoute parentMenuRoute = idToMenuRouteMap.get(menuRoute.getParentId());
                if (parentMenuRoute == null) {
                    rootMenus.add(menuRoute);
                    continue;
                }
                if (parentMenuRoute.getChildren() == null) {
                    parentMenuRoute.setChildren(new LinkedList<>());
                }
                parentMenuRoute.getChildren().add(menuRoute);
                if (menuRoute.getParentId() == null) {
                    rootMenus.add(parentMenuRoute);
                }
                // 有权限菜单列表里包含，在第一次循环里已经处理，无需重复作为中间菜单再次处理
                else if(!hasRightMenuIds.contains(parentMenuRoute.getId())){
                    newMiddleMenus.add(parentMenuRoute);
                }
            }
            middleMenus = newMiddleMenus;
        }

        List<MenuRoute> result = new LinkedList<>(rootMenus);
        formatData(result);

        return result;
    }

    /**
     * 根据Pure Admin前端的要求进行数据格式化
     * @param menuRoutes
     */
    private void formatData(List<MenuRoute> menuRoutes) {
        Collections.sort(menuRoutes);
        for (MenuRoute menuRoute : menuRoutes) {
            // 叶子节点不需要rank元素
            if (CollectionUtil.isEmpty(menuRoute.getChildren())) {
                menuRoute.getMeta().setRank(null);
            }
            else {
                formatData(menuRoute.getChildren());
            }
        }
    }

    private MenuRoute convertMenuRoute(Menu menu) {
        MenuRoute menuRoute = new MenuRoute();
        BeanUtils.copyProperties(menu, menuRoute);
        MenuRoute.MenuMeta meta = new MenuRoute.MenuMeta();
        BeanUtils.copyProperties(menu, meta);
        meta.setRank(menu.getPageRank());
        menuRoute.setMeta(meta);
        return menuRoute;
    }
}
